package main

import (
	"bytes"
	"fmt"
	"io"
	"math"
	"net"
	"strconv"
	"strings"
	"sync"
	"time"
)

const (
	SEVER_NETWORK="tcp"
	SEVER_ADDRESS="127.0.0.1:8818"
	// 数据切割标识
	DELIMITER='\t'
)

// socket实现进程通信与分布式通信框架

// 批量等待
var waitGroup sync.WaitGroup

// printLog -- 打印日志
func printLog(role string,sn int,format string,args... interface{}){
	// 后缀判断
	if !strings.HasSuffix(format,"\n"){
		format+="\n"
	}
	fmt.Printf("%s[%d]:%s",role,sn,fmt.Sprintf(format,args...))
}

// PrintClientLog -- 打印客户端日志
func PrintClientLog(clientId int,format string,args... interface{}){
	printLog("client",clientId,format,args)
}

// PrintServerLog -- 打印服务端日志
func PrintServerLog(format string,args... interface{}){
	printLog("server",0,format,args)
}

func StrToInt32(str string)(int32,error){
	// 转换成十进制
	num,err:=strconv.ParseInt(str,10,0)
	if nil!=err{
		return 0,err
	}

	if num>math.MaxInt32||num<math.MinInt32{
		return 0,err
	}

	return int32(num),nil
}

// GetCBrt-- 立方
func GetCBrt(num int32)float64{
	return math.Cbrt(float64(num))
}

// Read -- 读
func Read(conn net.Conn)(string,error){
	readBytes:=make([]byte,1)
	var buffer bytes.Buffer
	for {
		_,err:=conn.Read(readBytes)
		if nil!=err{
			return "",err
		}
		readByte:=readBytes[0]
		// 判断一下是否是分界字符
		if DELIMITER==readByte{
			break
		}
		buffer.WriteByte(readByte)

	}
	return buffer.String(),nil
}

// Write -- 写
func Write(conn net.Conn,content string)(int,error){
	var buffer bytes.Buffer
	buffer.WriteString(content)
	buffer.WriteByte(DELIMITER)
	return conn.Write(buffer.Bytes())
}

// HandleConnection -- 处理Server链接，收到一个整数，返回一个立方
func HandleConnection(conn net.Conn){
	defer func() {
		conn.Close()

		waitGroup.Done()
	}()

	for {
		// 最多等待10秒
		conn.SetReadDeadline(time.Now().Add(10*time.Second))

		readResult,readErr:=Read(conn)
		if nil!=readErr{
			if io.EOF==readErr{
				PrintServerLog("客户端关闭")
			}else{
				PrintServerLog("读取错误",readErr)
			}
			break
		}

		PrintServerLog("收到%s \n",conn.RemoteAddr(),readResult)
		result,resultErr:=StrToInt32(readResult)
		if nil!=resultErr{
			writeLen,writeErr:=Write(conn,readErr.Error())
			PrintServerLog("服务器错误",writeLen,writeErr)
			continue
		}
		//floatResult:=GetCBrt(result)

		floatResult:=float64(result*result*result)

		responseMsg:=fmt.Sprintf("%d->%f",result,floatResult)

		writeMsg,writeMsgErr:=Write(conn,responseMsg)

		if nil!=writeMsgErr{
			PrintServerLog("发送",writeMsg,writeMsgErr)
			continue
		}

		//PrintServerLog("%d->%f",result,floatResult)

		fmt.Println("整数:",result,"数据:",floatResult)


	}

}

// ServerGo --
func ServerGo(){
	listener,listenerErr:=net.Listen(SEVER_NETWORK,SEVER_ADDRESS)
	if nil!=listenerErr{
		fmt.Println("listenerErr:",listenerErr)
		return
	}

	defer listener.Close()

	fmt.Println("服务器开启", listener.Addr())

	for {
		// 接收链接
		conn,acceptErr:=listener.Accept()
		if nil!=acceptErr{
			PrintServerLog("%s",acceptErr)
			return
		}

		PrintServerLog("有客户加入",conn.RemoteAddr())

		// 为每一个客户端开启一个线程
		go HandleConnection(conn)

	}


}

// ClientGo --
func ClientGo(clientId int){
	defer waitGroup.Done()
	conn,connErr:=net.DialTimeout(SEVER_NETWORK,SEVER_ADDRESS,3*time.Second)
	if nil!=connErr{
		PrintClientLog(clientId,"%s",connErr)
		return
	}
	defer conn.Close()

	//PrintClientLog(clientId,"client %s -->server %s",conn.LocalAddr(),conn.RemoteAddr())

	fmt.Printf("%d, client %s -->server %s \n",clientId,conn.LocalAddr(),conn.RemoteAddr())

	time.Sleep(3*time.Second)

	conn.SetDeadline(time.Now().Add(5*time.Second))

	// 压入5数据
	for i:=0;i<5;i++{
		writeLen,writeErr:=Write(conn,fmt.Sprintf("%d",i))
		if nil!=writeErr{
			PrintClientLog(clientId,"%s",writeErr)
			continue
		}
		//PrintClientLog(clientId,"%d,%d",writeLen,i)
		fmt.Println(writeLen,"客户端压入:",clientId,"数据:",i)
	}

	// 压入5数据
	for j:=0;j<5;j++{
		readResult,readErr:=Read(conn)
		if nil!=readErr{
			if io.EOF==readErr{
				PrintClientLog(clientId,"%d close",clientId)
			}else{
				PrintClientLog(clientId,"%d %s",clientId,readErr)
			}

			continue
		}
		//PrintClientLog(clientId,"%d %s",clientId,readResult)
		fmt.Println("客户端读取:",clientId,"数据:",readResult)
	}

}

func main(){
	waitGroup.Add(2)

	go ServerGo()

	time.Sleep(2*time.Second)

	go ClientGo(1)

	go ClientGo(2)

	waitGroup.Wait()
}